package org.yzh.web.service;

import org.springframework.beans.factory.annotation.Value;
import com.rabbitmq.client.*;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson2.JSON;

/**
 * @author sanye
 */
@Service
public class RabbitMqService {

    final static String CHARSET_UTF8 = "UTF-8";
    /**
     * 交换器的类型，常见的如：fanout、direct、topic
     */
    final static String TYPE = "topic";
    /**
     * 交换器的名称
     */
    final static String EXCHANGE_NAME = "jt808";

    private Channel channel;
    private static final Logger log = LoggerFactory.getLogger(RabbitMqService.class.getSimpleName());

    public RabbitMqService(@Value("${rabbitmq.host}") String host, @Value("${rabbitmq.port}") int port,
            @Value("${rabbitmq.username}") String username, @Value("${rabbitmq.password}") String password,
            @Value("${rabbitmq.virtualhost}") String virtualhost, @Value("${rabbitmq.durable}") Boolean durable,
            @Value("${rabbitmq.autoDelete}") Boolean autoDelete) {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(host);
        factory.setPort(port);
        factory.setVirtualHost(virtualhost);
        factory.setUsername(username);
        factory.setPassword(password);
        // 自动重连
        factory.setAutomaticRecoveryEnabled(true);
        try {
            // JDK7语法 或⾃动关闭 connnection 和channel
            // 创建连接
            Connection connection = factory.newConnection();
            // 创建信道
            channel = connection.createChannel();
            // 指定转发——广播

            /**
             * exchange 交换器的名称
             * type 交换器的类型，常见的如：fanout、direct、topic
             * durable 是否持久化。为true，表示持久化，反之非持久化。持久化可以将交换器存储，在服务器重启的时候不会丢失信息。
             * autoDelete 是否自动删除。为true，表示自动删除。自动删除的前提是至少有一个队列或者交换器与交换器绑定，在所有队列或交换器被解绑后自动删除。
             * internal 是否是内置。为true，则表示是内置的交换器，客户端程序无法直接发送消息到这个交换器中，只能通过交换器路由到交换器这种方式。
             * argument 其他一些结构化参数，比如alternate-exchange
             */
            channel.exchangeDeclare(EXCHANGE_NAME, TYPE, durable, autoDelete, null);
            log.trace("***连接消息队列成功***");
        } catch (Exception e) {
            log.error("连接消息队列出错", e);
        }
    }

    public void publish(String message, String routingKey) {
        try {

            /**
             * exchange：交换器名称。指定消息需要发送到哪个交换器中。如果设置为空字符串，则消息会被发送到RabbitMQ默认的交换器中
             * routingKey：路由键，交换器根据路由键将消息存储到相应的队列中
             * 
             * props：消息的基本属性集，包含14个属性成员，分别有contentType、contentEncoding、headers(Map<String，Object>)、
             * deliveryMode、priority、correlationld、replyTo、expiration、messageld、timestamp、type、
             * userld、appld、clusterld。其中常用的几种都在上面的示例中进行了演示。
             * 
             * byte[] body：消息体（payload），真正需要发送的消息
             */
            channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes(CHARSET_UTF8));
        } catch (AlreadyClosedException ex) {
            log.error("往rabbitmq发数据报错,可能连接已关闭,尝试重连,data:", message, ex);
        } catch (Exception e) {
            log.error("往rabbitmq发数据报错,data:", message, e);
        }
    }

    public void publish(Object obj, String routingKey) {
        String message = JSON.toJSONString(obj);
        publish(message, routingKey);
    }
}